package com.cocolover2.andbase.widget.refresh;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.NestedScrollingChildHelper;
import android.support.v4.view.NestedScrollingParent;
import android.support.v4.view.NestedScrollingParentHelper;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.Scroller;

import com.cocolover2.andbase.R;
import com.cocolover2.andbase.utils.log.KLog;

/**
 * 下拉刷新布局
 * 1.下拉布局的高度建议是固定值
 */
@Deprecated
@SuppressWarnings("unused")
public class PullRefreshLayout extends ViewGroup implements NestedScrollingParent, NestedScrollingChild {
    public static final String TAG = PullRefreshLayout.class.getSimpleName();
    /**
     * 下拉过程->原始状态的默认滚动时间
     */
    private static final int PULL_TO_DEFAULT_SCROLL_DURATION = 200;
    /**
     * 释放->刷新状态的默认滚动时间
     */
    private static final int RELEASE_TO_REFRESHING_SCROLL_DURATION = 200;
    /**
     * 默认刷新完成的结果展示的停留时间
     */
    private static final int REFRESHED_DELAY_DURATION = 1000;
    /**
     * 刷新完成-->原始状态的默认滚动时间
     */
    private static final int REFRESHED_TO_DEFAULT_SCROLL_DURATION = 500;
    /**
     * 自动刷新时从原始->刷新状态的默认时间
     */
    private static final int AUTO_REFRESHING_SCROLL_DURATION = 800;
    /**
     * 默认的下拉阻力系数(系数越小越难拖动)
     */
    private static final float DEFAULT_DRAG_RATIO = 0.5f;
    //无效点
    private static final int INVALID_POINTER = -1;
    private static final int INVALID_COORDINATE = -1;

    //下拉-->原始的滚动周期
    private int mPullToDefaultScrollDuration = PULL_TO_DEFAULT_SCROLL_DURATION;
    //释放--->正在刷新的滚动周期
    private int mReleaseToRefreshingScrollDuration = RELEASE_TO_REFRESHING_SCROLL_DURATION;
    //刷新完成的结果展示的周期
    private int mRefreshedDelayDuration = REFRESHED_DELAY_DURATION;
    //刷新完成--->原始滚动周期
    private int mRefreshedToDefaultScrollDuration = REFRESHED_TO_DEFAULT_SCROLL_DURATION;
    //自动刷新的滚动周期
    private int mAutoRefreshScrollDuration = AUTO_REFRESHING_SCROLL_DURATION;
    /**
     * 拖动时的阻力系数，越小越难拖动（0~1.0）
     */
    private float mDragRatio = DEFAULT_DRAG_RATIO;

    private int mTouchSlop;
    //屏幕的高度
    private final int SCREEN_HEIGHT;
    /**
     * 下拉释放会触发刷新的阈值
     */
    private float mRefreshTriggerOffset;
    /**
     * 下拉拖动的最大距离
     */
    private float mRefreshFinalDragOffset;
    /**
     * 风格
     */
    private int mStyle = STYLE.CLASSIC;
    //是否启动刷新功能
    private boolean mRefreshEnabled = true;
    //内容布局
    private View mContentView;
    //下拉布局
    private View mHeaderView;
    //下拉布局的高度
    private int mHeaderHeight;

    /**
     * 拖动的距离偏移量
     */
    private int mTargetOffset;
    //下拉布局的偏移量
    private int mHeaderOffset;

    //上次的坐标
    private float mLastY;
    private float mLastX;
    //是否自动刷新
    private boolean mAutoRefresh = false;
    private RefreshCallBack mRefreshCallBack;
    //当前的状态
    private int mStatus = STATUS.STATUS_DEFAULT;
    //布局自动滚动管理
    private AutoScrollerManager mAutoScrollerManager;
    //刷新回调接口
    private OnRefreshListener mOnRefreshListener;

    /**
     * init touch action down point.y
     */
    private float mInitDownY;
    private float mInitDownX;
    /**
     * action touch pointer's id
     */
    private int mActivePointerId;

    //暂时无用
    protected int mTotalUnconsumed;
    protected boolean mNestedInProgress;
    //暂时未用
    protected int[] mParentOffsetInWindow = new int[2];
    private NestedScrollingChildHelper mNestedChildHelper = new NestedScrollingChildHelper(this);
    private NestedScrollingParentHelper mNestedParentHelper = new NestedScrollingParentHelper(this);
    private boolean mEnableNestedScroll = true;

    protected VelocityTracker mVelocityTracker;

    /**
     * the style enum
     */
    public static final class STYLE {
        //经典模式,刷新布局在底部
        public static final int CLASSIC = 0;
        //悬浮模式,刷新布局悬浮在内容上面
        public static final int ABOVE = 1;
    }

    public PullRefreshLayout(Context context) {
        this(context, null);
    }

    public PullRefreshLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public PullRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        SCREEN_HEIGHT = getResources().getDisplayMetrics().heightPixels;
        mAutoScrollerManager = new AutoScrollerManager();

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PullRefreshLayout);
        try {
            mPullToDefaultScrollDuration = array.getInt(R.styleable.PullRefreshLayout_duration_swipe_default, PULL_TO_DEFAULT_SCROLL_DURATION);
            mReleaseToRefreshingScrollDuration = array.getInt(R.styleable.PullRefreshLayout_duration_release_refreshing, RELEASE_TO_REFRESHING_SCROLL_DURATION);
            mRefreshedDelayDuration = array.getInt(R.styleable.PullRefreshLayout_duration_refresh_completed_delay, REFRESHED_DELAY_DURATION);
            mRefreshedToDefaultScrollDuration = array.getInt(R.styleable.PullRefreshLayout_duration_completed_default, REFRESHED_TO_DEFAULT_SCROLL_DURATION);
            mAutoRefreshScrollDuration = array.getInt(R.styleable.PullRefreshLayout_duration_default_refreshing, AUTO_REFRESHING_SCROLL_DURATION);
            mDragRatio = array.getFloat(R.styleable.PullRefreshLayout_drag_ratio, DEFAULT_DRAG_RATIO);

            mStyle = array.getInt(R.styleable.PullRefreshLayout_style, STYLE.CLASSIC);

            mRefreshTriggerOffset = array.getDimension(R.styleable.PullRefreshLayout_refresh_trigger_offset, 0);
            mRefreshFinalDragOffset = array.getDimension(R.styleable.PullRefreshLayout_refresh_final_trigger_offset, 0);
            if (mRefreshFinalDragOffset < mRefreshTriggerOffset) {
                mRefreshFinalDragOffset = mRefreshTriggerOffset * 2;
            }
        } finally {
            array.recycle();
        }

        setNestedScrollingEnabled(true);
        ensureVelocityTracker();
    }

    private void ensureVelocityTracker() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (getChildCount() != 1) {
            throw new RuntimeException(this.getClass().getSimpleName() + "必须有且只有一个子控件");
        }
        mContentView = getChildAt(0);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // header
        if (mHeaderView != null) {
            measureChildWithMargins(mHeaderView, widthMeasureSpec, 0, heightMeasureSpec, 0);
            MarginLayoutParams lp = ((MarginLayoutParams) mHeaderView.getLayoutParams());
            mHeaderHeight = mHeaderView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            /*
            * 防止未配置触发刷新的距离和最大拖动距离
            * 1.下拉布局的高度小于屏幕高度的一半,认为头部布局的高度是固定值,此时设置触发刷新的距离就是布局的高度
            * 2.如果不是时,就认为是头部布局是满屏的,此时会使用默认值 (SCREEN_HEIGHT / 8)
            * */
            if (mRefreshTriggerOffset == 0) {
                if (mHeaderHeight < SCREEN_HEIGHT / 2 && mRefreshTriggerOffset < mHeaderHeight) {
                    mRefreshTriggerOffset = mHeaderHeight;
                } else {
                    mRefreshTriggerOffset = SCREEN_HEIGHT / 8;
                }
                mRefreshFinalDragOffset = 2 * mRefreshTriggerOffset;
            }
        }
        // target
        if (mContentView != null) {
            measureChildWithMargins(mContentView, widthMeasureSpec, 0, heightMeasureSpec, 0);
        }
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        layoutChildren();
    }

    private void layoutChildren() {
        final int paddingLeft = getPaddingLeft();
        final int paddingTop = getPaddingTop();
        if (mContentView == null) {
            return;
        }
        layoutHeadView(paddingLeft, paddingTop);
        layoutTagerView(paddingLeft, paddingTop);

        if (mStyle == STYLE.CLASSIC || mStyle == STYLE.ABOVE) {
            if (mHeaderView != null) {
                mHeaderView.bringToFront();
            }
        }
    }


    private void layoutHeadView(int paddingLeft, int paddingTop) {
        // layout header
        if (mHeaderView != null) {
            final View headerView = mHeaderView;
            MarginLayoutParams lp = (MarginLayoutParams) headerView.getLayoutParams();
            final int headerLeft = paddingLeft + lp.leftMargin;
            final int headerTop;
            switch (mStyle) {
                case STYLE.CLASSIC:
                    // classic
                    headerTop = paddingTop + lp.topMargin - mHeaderHeight + mHeaderOffset;
                    break;
                case STYLE.ABOVE:
                    // classic
                    headerTop = paddingTop + lp.topMargin - mHeaderHeight + mHeaderOffset;
                    break;
                default:
                    // classic
                    headerTop = paddingTop + lp.topMargin - mHeaderHeight + mHeaderOffset;
                    break;
            }

            final int headerRight = headerLeft + headerView.getMeasuredWidth();
            final int headerBottom = headerTop + headerView.getMeasuredHeight();

            headerView.layout(headerLeft, headerTop, headerRight, headerBottom);
        }

    }

    private void layoutTagerView(int paddingLeft, int paddingTop) {
        // layout target
        if (mContentView != null) {
            final View targetView = mContentView;
            MarginLayoutParams lp = (MarginLayoutParams) targetView.getLayoutParams();
            final int targetLeft = paddingLeft + lp.leftMargin;
            final int targetTop;
            switch (mStyle) {
                case STYLE.CLASSIC:
                    // classic
                    targetTop = paddingTop + lp.topMargin + mTargetOffset;
                    break;
                case STYLE.ABOVE:
                    // above
                    targetTop = paddingTop + lp.topMargin;
                    break;
                default:
                    targetTop = paddingTop + lp.topMargin + mTargetOffset;
                    break;
            }
            final int targetRight = targetLeft + targetView.getMeasuredWidth();
            final int targetBottom = targetTop + targetView.getMeasuredHeight();
            targetView.layout(targetLeft, targetTop, targetRight, targetBottom);
        }

    }

    /**
     * 设置刷新的头部布局
     * implement of {@link OnSwipeTriggerListener}.
     *
     * @param view
     */
    public void setRefreshHeaderView(View view) {
        if (view instanceof OnSwipeTriggerListener) {
            if (mHeaderView != null && mHeaderView != view) {
                removeView(mHeaderView);
            }
            if (mHeaderView != view) {
                this.mHeaderView = view;
                addView(view);
            }
            mRefreshCallBack = new RefreshCallBack();
        } else {
            Log.e(TAG, "Refresh header view must be an implement of SwipeRefreshTrigger");
        }
    }

    public void setAutoRefreshScrollDuration(int duration) {
        mAutoRefreshScrollDuration = duration;
    }

    public void setRefreshedDelayDuration(int duration) {
        mRefreshedDelayDuration = duration;
    }

    public void setPullToDefaultScrollDuration(int duration) {
        mPullToDefaultScrollDuration = duration;
    }

    public void setReleaseToRefreshingScrollDuration(int duration) {
        mReleaseToRefreshingScrollDuration = duration;
    }

    public void setRefreshedToDefaultScrollDuration(int duration) {
        mRefreshedToDefaultScrollDuration = duration;
    }

    public void setDragRatio(float dragRatio) {
        mDragRatio = dragRatio;
    }

    public void setRefreshEnabled(boolean refreshEnabled) {
        mRefreshEnabled = refreshEnabled;
    }

    public void setRefreshTriggerOffset(float refreshTriggerOffset) {
        mRefreshTriggerOffset = refreshTriggerOffset;
    }

    public void setRefreshFinalDragOffset(int refreshFinalDragOffset) {
        mRefreshFinalDragOffset = refreshFinalDragOffset;
    }

    public View getHeaderView() {
        return mHeaderView;
    }

    /**
     * @param style
     * @see STYLE
     */
    public void setStyle(int style) {
        mStyle = style;
    }

    public static class LayoutParams extends MarginLayoutParams {

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        @SuppressWarnings({"unused"})
        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }
    }

    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new PullRefreshLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new PullRefreshLayout.LayoutParams(p);
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new PullRefreshLayout.LayoutParams(getContext(), attrs);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!mRefreshEnabled)
            return super.dispatchTouchEvent(ev);
        final int action = MotionEventCompat.getActionMasked(ev);
        switch (action) {
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                // swipeToRefresh -> finger up -> finger down if the status is still swipeToRefresh
                // in onInterceptTouchEvent ACTION_DOWN event will stop the scroller
                // if the event pass to the child view while ACTION_MOVE(condition is false)
                // in onInterceptTouchEvent ACTION_MOVE the ACTION_UP or ACTION_CANCEL will not be
                // passed to onInterceptTouchEvent and onTouchEvent. Instead It will be passed to
                // child view's onTouchEvent. So we must deal this situation in dispatchTouchEvent
                onActivePointerUp();
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    /**
     * on active finger up
     */
    private void onActivePointerUp() {
        if (STATUS.isSwipingToRefresh(mStatus)) {
            // 下拉状态
            mAutoScrollerManager.scrollSwipingToRefreshToDefault();
        } else if (STATUS.isReleaseToRefresh(mStatus)) {
            mAutoScrollerManager.scrollReleaseToRefreshToRefreshing();
            // 释放状态
            mRefreshCallBack.onRelease();
        } else if (STATUS.isRefreshing(mStatus)) {
            if (mTargetOffset > mHeaderHeight) {
                mAutoScrollerManager.scrollReleaseToRefreshToRefreshing();
            } else {
                mAutoScrollerManager.scrollRefreshingToDefault();
            }
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (!mRefreshEnabled)
            return super.onInterceptTouchEvent(event);
        final int action = MotionEventCompat.getActionMasked(event);

        if (mNestedInProgress) {
            return false;
        }
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mActivePointerId = MotionEventCompat.getPointerId(event, 0);
                mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
                mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
                // if it isn't an ing status or default status
                if (STATUS.isSwipingToRefresh(mStatus) || STATUS.isReleaseToRefresh(mStatus)) {
//                    // abort autoScrolling, not trigger the method #autoScrollFinished()
                    if (!mAutoRefresh) {
                        mAutoScrollerManager.abortIfRunning();
                        return true;
                    }
                }
                break;

            case MotionEvent.ACTION_MOVE:
                if (mActivePointerId == INVALID_POINTER) {
                    return false;
                }
                float y = getMotionEventY(event, mActivePointerId);
                float x = getMotionEventX(event, mActivePointerId);
                final float yInitDiff = y - mInitDownY;
                final float xInitDiff = x - mInitDownX;
                mLastY = y;
                mLastX = x;
                final boolean moved = Math.abs(yInitDiff) > Math.abs(xInitDiff);
                //拦截的条件:1想要下拉刷新,2.正在刷新中拖动布局且不是悬浮模式
                final boolean triggerCondition = (yInitDiff > 0 && moved && onCheckCanRefresh())
                        || (STATUS.isRefreshStatus(mStatus) && moved && mStyle != STYLE.ABOVE && mTargetOffset > 0);
                if (triggerCondition) {
                    return true;
                }
                break;

            case MotionEvent.ACTION_POINTER_UP:
                //多指操作时,离开屏幕记录位置
                onSecondaryPointerUp(event);
                mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
                mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                //单指操作离开后,位置在操作过程中已经记录过此处不需要记录
                mActivePointerId = INVALID_POINTER;
                break;
        }
        return super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!mRefreshEnabled)
            return super.onTouchEvent(event);

        final int action = MotionEventCompat.getActionMasked(event);

        if (mNestedInProgress) {
            return false;
        }

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mActivePointerId = MotionEventCompat.getPointerId(event, 0);
                return true;

            case MotionEvent.ACTION_MOVE:
                // take over the ACTION_MOVE event from SwipeToLoadLayout#onInterceptTouchEvent()
                // if condition is true
                final float y = getMotionEventY(event, mActivePointerId);
                final float x = getMotionEventX(event, mActivePointerId);

                final float yDiff = y - mLastY;
                final float xDiff = x - mLastX;
                mLastY = y;
                mLastX = x;

                if (Math.abs(xDiff) > Math.abs(yDiff) && Math.abs(xDiff) > mTouchSlop) {
                    return false;
                }
                moveRefreshedHeader(yDiff);
                return true;
            case MotionEvent.ACTION_POINTER_DOWN:
                final int pointerIndex = MotionEventCompat.getActionIndex(event);
                final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex);
                if (pointerId != INVALID_POINTER) {
                    mActivePointerId = pointerId;
                }
                mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
                mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
                break;

            case MotionEvent.ACTION_POINTER_UP:
                onSecondaryPointerUp(event);
                mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
                mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (mActivePointerId == INVALID_POINTER) {
                    return false;
                }
                mActivePointerId = INVALID_POINTER;
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }

    /**
     * @param isAutoFix 在正在刷新的状态下才有效
     */
    private void fixCurrentStatusLayout(boolean isAutoFix) {
        if (STATUS.isRefreshing(mStatus)) {
//            if (isAutoFix) {
//                mTargetOffset = (int) (mHeaderHeight + 0.5f);
//                mHeaderOffset = mTargetOffset;
//            } else
            if (mTargetOffset < 0) {
                mTargetOffset = 0;
                mHeaderOffset = 0;
            }
            layoutChildren();
            invalidate();
        } else if (STATUS.isStatusDefault(mStatus)) {
            mTargetOffset = 0;
            mHeaderOffset = 0;
            layoutChildren();
            invalidate();
        }
    }


    private float getMotionEventY(MotionEvent event, int activePointerId) {
        final int index = MotionEventCompat.findPointerIndex(event, activePointerId);
        if (index < 0) {
            return INVALID_COORDINATE;
        }
        return MotionEventCompat.getY(event, index);
    }

    private float getMotionEventX(MotionEvent event, int activePointId) {
        final int index = MotionEventCompat.findPointerIndex(event, activePointId);
        if (index < 0) {
            return INVALID_COORDINATE;
        }
        return MotionEventCompat.getX(event, index);
    }

    private boolean onCheckCanRefresh() {
        return mRefreshEnabled && !canChildScrollUp() && mHeaderView != null && mRefreshTriggerOffset > 0;
    }

    /**
     * 判断子布局能否继续向上滚动
     *
     * @return
     */
    @SuppressWarnings("all")
    protected boolean canChildScrollUp() {
        if (android.os.Build.VERSION.SDK_INT < 14) {
            if (mContentView instanceof AbsListView) {
                final AbsListView absListView = (AbsListView) mContentView;
                return absListView.getChildCount() > 0
                        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
                        .getTop() < absListView.getPaddingTop());
            } else {
                return ViewCompat.canScrollVertically(mContentView, -1) || mContentView.getScrollY() > 0;
            }
        } else {
            return ViewCompat.canScrollVertically(mContentView, -1);
        }
    }

    private void onSecondaryPointerUp(MotionEvent ev) {
        final int pointerIndex = MotionEventCompat.getActionIndex(ev);
        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
        if (pointerId == mActivePointerId) {
            // This was our active pointer going up. Choose a new
            // active pointer and adjust accordingly.
            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
        }
    }

    /**
     * 手指拖动视图滚动
     *
     * @param yDiff       滚动的原始距离
     * @param isUserRatio 是否使用阻尼参数
     */
    private void fingerScroll(float yDiff, boolean isUserRatio) {
        if (mDragRatio > 1) mDragRatio = 1.0f;
        float yScrolled = 0;
        if (isUserRatio) {
            yScrolled = yDiff * mDragRatio;
        } else {
            yScrolled = yDiff;
        }

        final float tmpTargetOffset = yScrolled + mTargetOffset;

        //滑动最大距离
        if (mRefreshFinalDragOffset >= mRefreshTriggerOffset && tmpTargetOffset > mRefreshFinalDragOffset) {
            yScrolled = mRefreshFinalDragOffset - mTargetOffset;
        }

        if (STATUS.isReleaseToRefresh(mStatus) || STATUS.isSwipingToRefresh(mStatus)) {
            mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, false);
            //处理在正在刷新状态时,用手指进行滑动屏幕的操作
        } else if (STATUS.isRefreshing(mStatus)) {
            mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, false);
        }

        //当处于刷成完成状态时,手指滚动屏幕失效
        if (!STATUS.isRefreshCompleted(mStatus)) {
            invalidateScoll(yScrolled);
        }
    }

    /**
     * 手指离开屏幕时滚动布局
     *
     * @param yScrolled 滚动偏移量
     */
    private void autoScroll(final float yScrolled) {
        if (mAutoRefresh) {//自动刷新时，滚动布局
            if (STATUS.isSwipingToRefresh(mStatus)) {
                mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, true);
            } else if (STATUS.isReleaseToRefresh(mStatus)) {
                mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, true);
            } else if (STATUS.isRefreshing(mStatus)) {
                mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, true);
            }
        }
        //防止在正在刷新状态或者释放触发刷新状态时,自动滚动到正在刷新界面时,距离小于设置的初始间距造成的闪烁
//        if (STATUS.isRefreshing(mStatus) || STATUS.isReleaseToRefresh(mStatus)) {
//            if (mTargetOffset + yScrolled < mHeaderHeight)
//                return;
//        }
        invalidateScoll(yScrolled);
    }

    /**
     * 滚动当前布局
     *
     * @param yScrolled 滚动的偏移量
     */
    private void invalidateScoll(final float yScrolled) {
        if (yScrolled == 0) {
            return;
        }
        mTargetOffset += yScrolled;
        if (mTargetOffset < 0) {
            mTargetOffset = 0;
        }
        mHeaderOffset = mTargetOffset;
        layoutChildren();
        invalidate();
    }


    private void setStatus(int status) {
        mStatus = status;
    }

    public void setOnRefreshListener(OnRefreshListener listener) {
        mOnRefreshListener = listener;
    }


    /**
     * 刷新的整体状态有4种
     * 1.默认状态
     * 2.下拉状态
     * 3.释放状态
     * 4.正在刷新状态
     */
    private final static class STATUS {
        private static final int STATUS_REFRESH_COMPLETED = -4;
        //正在刷新状态
        private static final int STATUS_REFRESHING = -3;
        //释放状态
        private static final int STATUS_RELEASE_TO_REFRESH = -2;
        //下拉还没有到达释放状态的过程状态
        private static final int STATUS_SWIPING_TO_REFRESH = -1;
        //原始状态
        private static final int STATUS_DEFAULT = 0;


        private static boolean isRefreshing(final int status) {
            return status == STATUS.STATUS_REFRESHING;
        }

        private static boolean isRefreshStatus(final int status) {
            return status < STATUS_DEFAULT;
        }

        private static boolean isReleaseToRefresh(final int status) {
            return status == STATUS.STATUS_RELEASE_TO_REFRESH;
        }

        private static boolean isSwipingToRefresh(final int status) {
            return status == STATUS.STATUS_SWIPING_TO_REFRESH;
        }

        private static boolean isStatusDefault(final int status) {
            return status == STATUS.STATUS_DEFAULT;
        }

        private static boolean isRefreshCompleted(final int status) {
            return status == STATUS.STATUS_REFRESH_COMPLETED;
        }
    }

    /**
     * 下拉刷新过程各种状态的回调
     */
    private class RefreshCallBack implements OnSwipeTriggerListener {
        OnSwipeTriggerListener mHeaderViewTrigger;

        RefreshCallBack() {
            if (mHeaderView != null && mHeaderView instanceof OnSwipeTriggerListener) {
                mHeaderViewTrigger = (OnSwipeTriggerListener) mHeaderView;
            } else {
                throw new IllegalArgumentException("HeaderView is null or not instanceof OnSwipeTriggerListener");
            }
        }

        void onPrepare() {
            if (mHeaderView.getVisibility() != VISIBLE)
                mHeaderView.setVisibility(VISIBLE);
        }

        @Override
        public void onMove(int y, float refreshTriggerOffset, boolean automatic) {
            if (mHeaderView.getVisibility() != VISIBLE)
                mHeaderView.setVisibility(VISIBLE);
            mHeaderViewTrigger.onMove(y, refreshTriggerOffset, automatic);
        }

        @Override
        public void onRelease() {
            mHeaderViewTrigger.onRelease();
        }

        @Override
        public void onRefresh() {
            mHeaderViewTrigger.onRefresh();
            if (mOnRefreshListener != null)
                mOnRefreshListener.onRefresh();
        }

        @Override
        public void onComplete(String statusMsg) {
            mHeaderViewTrigger.onComplete(statusMsg);
        }

        @Override
        public void onReset() {
            mHeaderViewTrigger.onReset();
            mHeaderView.setVisibility(GONE);
        }
    }

    /**
     * 自动滚动结束后的状态处理
     */
    private void autoScrollFinished() {
        if (STATUS.isReleaseToRefresh(mStatus)) {
            setStatus(STATUS.STATUS_REFRESHING);
            fixCurrentStatusLayout(true);
            mRefreshCallBack.onRefresh();
        } else if (STATUS.isRefreshing(mStatus)) {
            fixCurrentStatusLayout(true);
        } else if (STATUS.isSwipingToRefresh(mStatus)) {
            if (!mAutoRefresh) {
                setStatus(STATUS.STATUS_DEFAULT);
                fixCurrentStatusLayout(true);
                mRefreshCallBack.onReset();
            } else {
                mAutoRefresh = false;
                setStatus(STATUS.STATUS_REFRESHING);
                fixCurrentStatusLayout(true);
                mRefreshCallBack.onRefresh();
            }
        } else if (STATUS.isRefreshCompleted(mStatus)) {
            setStatus(STATUS.STATUS_DEFAULT);
            fixCurrentStatusLayout(true);
            mRefreshCallBack.onReset();
        }

    }

    /**
     * 刷新完成
     */
    public void refreshCompleted(String statusMsg) {
        if (!mRefreshEnabled || mHeaderView == null) {
            return;
        }
        setStatus(STATUS.STATUS_REFRESH_COMPLETED);
        mRefreshCallBack.onComplete(statusMsg);
        postDelayed(new Runnable() {
            @Override
            public void run() {
                mAutoScrollerManager.scrollRefreshingToDefault();
            }
        }, mRefreshedDelayDuration);
    }

    //自动刷新
    public void autoRefresh() {
        if (!mRefreshEnabled || mHeaderView == null) {
            return;
        }
        mAutoRefresh = true;
        post(new Runnable() {
            @Override
            public void run() {
                if (STATUS.isStatusDefault(mStatus)) {
                    setStatus(STATUS.STATUS_SWIPING_TO_REFRESH);
                    mAutoScrollerManager.scrollDefaultToRefreshing();
                }
            }
        });

    }


    /**
     * 自动滚动管理者
     */
    @Deprecated
    private final class AutoScrollerManager {
        private Scroller mScroller;

        private int mmLastY;

        private boolean mRunning = false;

        private boolean mAbort = false;

        private boolean mIsFrist;

        AutoScrollerManager() {
            mScroller = new Scroller(getContext());
        }

        private final Runnable autoScrollRunnable = new Runnable() {
            @Override
            public void run() {
                int currY = mScroller.getCurrY();
                if (mIsFrist && currY == mmLastY) {//由于mScroller会记录上一次的Y的坐标,这里重置一下,防止滚动时,界面闪烁
                    currY = mmLastY = 0;
                    mIsFrist = false;
                }
                final int yDiff = currY - mmLastY;
                if (!mScroller.computeScrollOffset() || mScroller.isFinished()) {
                    finishScorll();
                } else {
                    mmLastY = currY;
                    PullRefreshLayout.this.autoScroll(yDiff);
                    post(this);
                }
            }
        };

        private void finishScorll() {
            mRunning = false;
            removeCallbacks(autoScrollRunnable);
            // if abort by user, don't call
            if (!mAbort) {
                autoScrollFinished();
            }
        }

        /**
         * abort scroll if it is scrolling
         */
        void abortIfRunning() {
            if (mRunning) {
                if (!mScroller.isFinished()) {
                    mAbort = true;
                    mScroller.forceFinished(true);
                }
                finishScorll();
                mAbort = false;
            }
        }

        private void autoScroll(int yScrolled, int duration) {
            removeCallbacks(autoScrollRunnable);
            mmLastY = mScroller.getCurrY();
            mIsFrist = true;
            if (!mScroller.isFinished()) {
                mScroller.forceFinished(true);
            }
            mScroller.startScroll(0, 0, 0, yScrolled, duration);
            post(autoScrollRunnable);
            mRunning = true;
        }

        private void fling(int velocityY) {
            removeCallbacks(autoScrollRunnable);
            mmLastY = mScroller.getCurrY();
            mIsFrist = true;
            if (!mScroller.isFinished()) {
                mScroller.forceFinished(true);
            }
            mScroller.startScroll(0, 0, 0, -mTargetOffset, computeDuration(velocityY));
            post(autoScrollRunnable);
            mRunning = true;
        }

        //原始状态——->正在刷新状态(用于自动刷新)
        void scrollDefaultToRefreshing() {
            autoScroll((int) (mHeaderHeight + 0.5f), mAutoRefreshScrollDuration);
        }

        //下拉状态--->原始状态
        void scrollSwipingToRefreshToDefault() {
            autoScroll(-mHeaderOffset, mPullToDefaultScrollDuration);
        }

        //释放状态--->正在刷新状态
        void scrollReleaseToRefreshToRefreshing() {
            autoScroll((int) (mHeaderHeight + 0.5f) - mHeaderOffset, mReleaseToRefreshingScrollDuration);
        }

        //正在刷新--->原始状态
        void scrollRefreshingToDefault() {
            autoScroll(-mHeaderOffset, mRefreshedToDefaultScrollDuration);
        }
        void scrollRefreshingToDefault2() {
            autoScroll(-mHeaderOffset, 10);
        }
    }


    /**
     * 设置是否支持嵌套滚动
     *
     * @param enableNestedScroll true 支持
     */
    public void setEnableNestedScroll(boolean enableNestedScroll) {
        mEnableNestedScroll = enableNestedScroll;
    }

    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        final View thisView = this;
        boolean accepted = thisView.isEnabled() && isNestedScrollingEnabled() && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
        accepted = accepted && mRefreshEnabled && mEnableNestedScroll;
        return accepted;
    }

    @Override
    public void onNestedScrollAccepted(View child, View target, int axes) {
        // Reset the counter of how much leftover scroll needs to be consumed.
        mNestedParentHelper.onNestedScrollAccepted(child, target, axes);
        mTotalUnconsumed = 0;
        mNestedInProgress = true;
        // Dispatch up to the nested parent
        startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
    }


    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
//        KLog.e(mTargetOffset + "#" + mStatus + "#" + velocityY + "#" + mHeaderOffset);
        if ((STATUS.isRefreshing(mStatus) || STATUS.isRefreshCompleted(mStatus)) && mTargetOffset > 0 && velocityY > 0) {
            mAutoScrollerManager.fling((int) velocityY);
            KLog.e("==========>||" + mHeaderOffset);
            return true;
        } else {
            return dispatchNestedPreFling(velocityX, velocityY);
        }
    }

    @Override
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
        return dispatchNestedFling(velocityX, velocityY, consumed);
    }

    //执行于子布局滚动之前
    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        int dyConsumed = 0;
        /* 刷新布局显示出来，并且子布局向上滚动，消耗y轴偏移量*/
        if (mTargetOffset > 0 && dy > 0) {
            if (mTargetOffset > dy) {
                dyConsumed = dy;
            } else {
                dyConsumed = mTargetOffset;
            }
            changeRefreshStatusByMove(-dyConsumed);
            fingerScroll(-dyConsumed, false);
            consumed[1] = dyConsumed;
        } else {
            dispatchNestedPreScroll(dx, dy - consumed[1], consumed, null);
        }
    }

    //执行于子布局滚动之后
    @Override
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
        final int dy = dyUnconsumed + mParentOffsetInWindow[1];
        if (dy < 0 && !canChildScrollUp()) {
            mTotalUnconsumed += Math.abs(dy);
            moveRefreshedHeader(-dyUnconsumed);
        }
    }

    /**
     * 移动刷新布局
     *
     * @param scrollOffset 滚动偏移量
     */
    private void moveRefreshedHeader(float scrollOffset) {
        changeRefreshStatusByMove(scrollOffset);
                /*
                * 1.当不能向上滑动时
                * 2.当是悬浮模式时,不在正在刷新状态
                * 满足以上情况时,才可用手指拖动布局,触发下拉刷新布局
                * */
        if (!canChildScrollUp() && !(STATUS.isRefreshing(mStatus) && mStyle == STYLE.ABOVE)) {
            fingerScroll(scrollOffset, true);
        }
    }

    private void changeRefreshStatusByMove(float scrollOffset) {
        if (STATUS.isStatusDefault(mStatus)) {
            if (scrollOffset > 0 && onCheckCanRefresh()) {
                setStatus(STATUS.STATUS_SWIPING_TO_REFRESH);
                mRefreshCallBack.onPrepare();
            }
        }
        if ((STATUS.isSwipingToRefresh(mStatus) || STATUS.isReleaseToRefresh(mStatus))) {
            if (mTargetOffset <= 0) {
                setStatus(STATUS.STATUS_DEFAULT);
                fixCurrentStatusLayout(false);
            } else if (mTargetOffset >= mRefreshTriggerOffset) {
                setStatus(STATUS.STATUS_RELEASE_TO_REFRESH);
            } else {
                setStatus(STATUS.STATUS_SWIPING_TO_REFRESH);
            }
        } else if (STATUS.isRefreshing(mStatus)) {//处理正在刷新是拖动布局的情况
            fixCurrentStatusLayout(false);
        }
    }

    @Override
    public void onStopNestedScroll(View child) {
        mNestedParentHelper.onStopNestedScroll(child);
        mNestedInProgress = false;
        // Finish the spinner for nested scrolling if we ever consumed any
        // unconsumed nested scroll
        if (mTotalUnconsumed > 0) {
//            finishSpinner(mTotalUnconsumed);
            mTotalUnconsumed = 0;
        }
        // Dispatch up our nested parent
        stopNestedScroll();
    }

    /**
     * {@link NestedScrollingChild}
     */
    // NestedScrollingChild
    @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        mNestedChildHelper.setNestedScrollingEnabled(enabled);
    }

    @Override
    public boolean isNestedScrollingEnabled() {
        return mNestedChildHelper.isNestedScrollingEnabled();
    }

    @Override
    public boolean startNestedScroll(int axes) {
        return mNestedChildHelper.startNestedScroll(axes);
    }

    @Override
    public void stopNestedScroll() {
        mNestedChildHelper.stopNestedScroll();
    }

    @Override
    public boolean hasNestedScrollingParent() {
        return mNestedChildHelper.hasNestedScrollingParent();
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
                                        int dyUnconsumed, int[] offsetInWindow) {
        return mNestedChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
                dxUnconsumed, dyUnconsumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
        return mNestedChildHelper.dispatchNestedPreScroll(
                dx, dy, consumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        return mNestedChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        return mNestedChildHelper.dispatchNestedPreFling(velocityX, velocityY);
    }


    /**
     * 根据速度计算滚动动画持续时间
     *
     * @param velocityY
     * @return
     */
    private int computeDuration(float velocityY) {
        final int distance;
        if (velocityY > 0) {
            distance = Math.abs(mHeaderView.getHeight() - getScrollY());
        } else {
            distance = Math.abs(mHeaderView.getHeight() - (mHeaderView.getHeight() - getScrollY()));
        }


        final int duration;
        velocityY = Math.abs(velocityY);
        if (velocityY > 0) {
            duration = 3 * Math.round(1000 * (distance / velocityY));
            Log.e(TAG, "===计算时间==11=" + distance + "#" + duration + "#" + distance / velocityY + "#" + Math.round(1000 * (distance / velocityY)));
        } else {
            final float distanceRatio = (float) distance / getHeight();
            duration = (int) ((distanceRatio + 1) * 150);
        }
        Log.e(TAG, "===计算时间===" + distance + "#" + duration);

        return duration;
    }


    public void scroll(int offsetY) {
        KLog.e(offsetY + "#"+mTargetOffset+"#"+mHeaderOffset);
        if (mTargetOffset > 0) {
            mAutoScrollerManager.scrollRefreshingToDefault2();
        }
        mContentView.scrollBy(0, offsetY);
    }
}


